{\rtf0\ansi{\fonttbl\f0\fmodern Courier;\f1\ftech Symbol;\f2\fmodern Ohlfs;}
\margl40
\margr40
{\colortbl;\red0\green0\blue0;}
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs24\fc0\cf0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//
\i 	
\b FILENAME
\b0 :	
\b\i0 eTDocUI.m\

\b0 //
\i 	
\b SUMMARY
\b0 :	
\b\i0 Implementation of the UI & Window management of eTDoc documents.
\b0 \
//	
\b\i SUPERCLASS
\b0 :
\i0 	
\b Object:eTDocUI
\b0 \
//	
\b\i PROTOCOLS
\b0 :
\i0 	
\b <DocNotification>, uses <Agent>
\b0 \
//	
\b\i INTERFACE
\b0 :
\i0 	
\b eTDocUI.nib
\b0 \
//	
\b\i AUTHOR
\b0 :		
\b\i0 Rohit Khare
\b0 \
//	
\b\i COPYRIGHT
\b0 :	
\f1\i0 с
\f0\b 1993,94 California Institure of Technology, eText Project\

\b0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i Implementation Comments
\b0\i0 \
//		This is a 
\i large
\i0  class. Luckily, the functionality under each of the\
//	headings is relatively independent of any other. To settle jurisdiction \
//	issues between 
\i eTDoc
\i0  and 
\i eTDocUI
\i0 , pay attention to which class owns the \
//	resource in question (from the 
\i @interface
\i0  declaration).\
//\
//		A new twist: 
\i etDocUI
\i0  itself registers for 
\i docNotification
\i0 , and thus\
//	maintains the file 
\b .etUIinfo
\b0  in the corpus: 
\i printinfo
\i0 , 
\i window size
\i0 , and\
//	the height of the 
\i splitview
\i0 . Also, 
\i the last selection
\i0  -- we can choose\
//	not to restore it if the reader != owner.\
//\
//		Should we change the policy preventing saving untouched documents?\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i HISTORY
\b0\i0 \
//	12/23/94:	
\b Added default to suppress HTMD warning.
\i \

\b0\i0 //	10/30/94:	
\b Added miniwindow support.
\i \

\b0\i0 //	10/05/94:	
\b Revamped for eText5.
\i \

\b0\i0 //	08/05/94:	
\b Removed ChangeManager, migrated to UndoManager. RK
\b0 \
//	05/13/94:	
\b Added support for etUIinfo, <DocNotification>
\b0 \
//	01/14/94:	
\b Revised extensively for eText4.0
\b0 \
//	08/20/93:	
\b Created.
\b0 \
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Imported Interfaces
\b0 \
//\
	#import "
\b eTDocUI.h
\b0 "\
	#import "
\b eTContainerView.h
\b0 "\
\
#define 
\b HTMD_WARNED
\b0  "
\b SuppressHTMDWarning
\b0 "\
\

\i @implementation eTDocUI\

\i0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
// 	
\b Class Management
\b0 \
//\
+ 
\b initialize
\b0  \{\
	[
\b userModel
\b0  
\b defaultValue
\b0 :"
\b NO
\b0 " for:
\b HTMD_WARNED
\b0 ];\
	return self;\
\}\
\
- 
\b init
\b0  \{\
	char        
\b buf
\b0 [MAXPATHLEN];\
	NXBundle   *
\b bundle
\b0 ;\
\
	[super init];\
	
\b theAgent
\b0  = 
\b nil
\b0 ;\
	
\b printInfo
\b0  = 
\b nil
\b0 ;\
	
\b etDoc
\b0  = 
\b nil
\b0 ;\
	
\b bundle
\b0  = [
\b NXBundle
\b0  bundleForClass:[
\b eTDocUI
\b0  class]];\
	if ([
\b bundle
\b0  
\b getPath
\b0 :buf 
\b forResource
\b0 :"
\b eTDocUI
\b0 " 
\b ofType
\b0 :"
\b nib
\b0 "] ) \{\
		[NXApp 
\b loadNibFile
\b0 :buf 
\b owner
\b0 :self 
\b withNames
\b0 :NO];\
	\} else \{\
		NXLogError("
\b NIB not found: eTDocUI
\b0 ");\
	\}\
	return self;\
\}\
- 
\b free
\b0  \{\
	//
\i Commented out by RK on 8/22; put back in eText5
\i0     \
    if ([
\b NXApp
\b0  
\b printInfo
\b0 ] == 
\b printInfo
\b0 ) [NXApp 
\b setPrintInfo
\b0 :
\b nil
\b0 ];\

\i 	// Taken back out on 12/1 -- can't see why, but it fails.\
	// [NXApp delayedFree:
\b printInfo
\b0 ];\

\i0 	\
	[etDoc 
\b setSelectedObj
\b0 : 
\b nil
\b0 ];\
	//
\i [etDoc 
\b unregisterNotification
\b0 :
\b self
\b0 ]; Why Bother?
\i0 \
	theAgent = [
\b theAgent
\b0  free];\
	theContainer = [
\b theContainer
\b0  free];\
	[
\b theWindow
\b0  
\b setDelegate
\b0 :
\b nil
\b0 ];\
	eTextObj = [
\b eTextObj
\b0  free]; \
	theWindow = [
\b theWindow
\b0  close];\
	//
\i  possible fix, 8/22 since TE will do the next freewhencosed.
\i0 \
	//
\i  eTextObj will be freed automagically. eTDoc is still alive here
\i0 \
	//
\i  Paranoia!
\i0 \
	NXPing();\
	return self = [super free];\
\}\
- 
\b awakeFromNib
\b0  \{\
	
\b static
\b0  
\b int
\b0  	
\b i=0
\b0 ;\
	
\b NXRect
\b0 		
\b r
\b0 ;\
	\
	//  
\i User Interface Initialization
\i0 : 
\i load in the eText + ScrollView
\i0 \
	[theWindow 
\b disableDisplay
\b0 ];\
	[
\b theSplitview
\b0  
\b addSubview
\b0 :
\b theScroller
\b0 ];\
	[
\b theScroller
\b0  
\b getContentSize
\b0 :&(
\b r
\b0 .size)];\
	[eTextObj 
\b setVertResizable
\b0 :YES];\
	[eTextObj 
\b setHorizResizable
\b0 :NO];\
	[eTextObj 
\b sizeTo
\b0 :
\b r
\b0 .size.
\b width
\b0  :
\b r
\b0 .size.
\b height
\b0 ];\
	[eTextObj 
\b setMinSize
\b0 :&(
\b r
\b0 .size)];\
	
\b r
\b0 .size.
\b width
\b0  = 
\b MAXFLOAT
\b0 ; 
\b r
\b0 .size.
\b height
\b0  = 
\b MAXFLOAT
\b0 ;\
	[eTextObj 
\b setMaxSize
\b0 :&(
\b r
\b0 .size)];\
	// 
\i Lay out the window at an offset
\i0 \
	[
\b theWindow
\b0  
\b getFrame
\b0 :&r];\
	[theWindow 
\b moveTo
\b0 :r.origin.x + (
\b i
\b0 %10) * 
\b 22
\b0  :r.origin.y - (
\b i
\b0 %10) * 
\b 22
\b0 ];\
	
\b i++
\b0 ;\
	// 
\i Display the window
\i0 \
	[[theWindow 
\b reenableDisplay
\b0 ] 
\b display
\b0 ];\
	return self;\
\}\
- 
\b setDoc
\b0 :theDoc \{\
	char 		
\b RTFfile
\b0 [MAXPATHLEN];\
	\
	
\b etDoc
\b0  = 
\b theDoc
\b0 ;\
	[etDoc 
\b registerNotification
\b0 :
\b self
\b0 ];\
	[
\b eTextObj
\b0  
\b setDoc
\b0 :
\b etDoc
\b0 ];	\
	[theWindow 
\b disableDisplay
\b0 ];\
	[[etDoc 
\b undoManager
\b0 ] 
\b disableUndoRegistration
\b0 ];\
	\
	// 
\i Read in 
\i0 .etUInfo
\i  parameters
\i0 \
	if (
\b !access
\b0 ([[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ], 
\b R_OK
\b0 )) \{\
		
\b NXStream
\b0  	*
\b s
\b0 ;\
		
\b float
\b0  		
\b dh
\b0 , 
\b h
\b0 , 
\b w
\b0 ;\
				\
		
\b sprintf
\b0 (
\b RTFfile
\b0 , "
\b %s/
\b0 "
\b UIINFOFILE
\b0 , [[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]);\
		
\b s
\b0  = 
\b NXOpenTypedStreamForFile
\b0 (RTFfile, 
\b NX_READONLY
\b0 );\
		if (!s) \{						// 
\i eText4 Compatibility\

\b\i0 			sprintf
\b0 (
\b RTFfile
\b0 , "
\b %s/
\b0 "
\b UIINFOFILE2
\b0 , [[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]);\

\b 			s
\b0  = 
\b NXOpenTypedStreamForFile
\b0 (RTFfile, 
\b NX_READONLY
\b0 );\
		\}\
		if (
\b s
\b0 ) \{\
			
\b NXRect
\b0  
\b r
\b0 ;\
			\
			
\b printInfo
\b0  = 
\b NXReadObject
\b0 (s);\
			
\b NXReadTypes
\b0 (s,"
\b fffii
\b0 ", &
\b dh
\b0 ,&
\b h
\b0 ,&
\b w
\b0 ,&
\b begin
\b0 ,&
\b end
\b0 );\
			[
\b theWindow
\b0  
\b getFrame
\b0 :&
\b r
\b0 ];\
			r.origin.y += r.size.height - 
\b h
\b0 ;\
			r.size.height = 
\b MIN
\b0 (
\b h
\b0 , 
\b r.origin.y + r.size.height
\b0 ); // 
\i don't fall off the bottom
\i0 \
			r.size.width = 
\b w
\b0 ;\
			[theWindow 
\b placeWindow
\b0 :&
\b r
\b0 ];\
			// 
\i we can't invert this operation: [theSplitview dh];
\i0 \
			if ([eTextObj 
\b isEditable
\b0 ]) [
\b eTextObj
\b0  
\b setSel
\b0 :
\b begin
\b0  :
\b end
\b0 ];\
			
\b NXCloseTypedStream
\b0 (s);\
		\}\
	\} else \{\
		[eTextObj 
\b setEditable
\b0 :YES];\
	\}\
	[theWindow 
\b setTitleAsFilename
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]];\
	if (!printInfo) printInfo = [[
\b NXApp
\b0  
\b printInfo
\b0 ] 
\b copy
\b0 ];\
	[NXApp 
\b setPrintInfo
\b0 :printInfo];\
	[theWindow 
\b setDocEdited
\b0 :
\b NO
\b0 ];	\
	[[etDoc 
\b undoManager
\b0 ] 
\b reenableUndoRegistration
\b0 ];\
	[[theWindow 
\b reenableDisplay
\b0 ] 
\b display
\b0 ];\
	[theWindow 
\b makeKeyAndOrderFront
\b0 :self];\
	[theWindow 
\b makeFirstResponder
\b0 :
\b eTextObj
\b0 ];\
	[inspector 
\b inspect
\b0 :[
\b etDoc
\b0  
\b selectedObj
\b0 ]];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
// 	
\b FirstResponder Callbacks
\b0 \
//\
- 
\b undo
\b0 :sender \{\
	[theWindow 
\b disableFlushWindow
\b0 ];\
	[[etDoc 
\b undoManager
\b0 ] 
\b undo
\b0 :sender];\
	[eTextObj 
\b calcLine
\b0 ];\
	[[theWindow 
\b reenableFlushWindow
\b0 ] 
\b\fc1\cf1 flushWindowIfNeeded
\b0\fc0\cf0 ];\
	return self;\}\
- 
\b redo
\b0 :sender \{\
	[theWindow 
\b disableFlushWindow
\b0 ];\
	[[etDoc 
\b undoManager
\b0 ] 
\b redo
\b0 :sender];\
	[eTextObj 
\b calcLine
\b0 ];\
	[[theWindow 
\b reenableFlushWindow
\b0 ] 
\b\fc1\cf1 flushWindowIfNeeded
\b0\fc0\cf0 ];\
	return self;\}\
\
\
- 
\b save
\b0 :sender \{\
	if ([self 
\b needsSaving
\b0 ]) \{\
		if (*[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ] && 
\b !
\b0 [[etDoc 
\b docInfo
\b0 ] 
\b isVirgin
\b0 ]) \{\
			[
\b etDoc
\b0  
\b saveTo
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ] \
			     
\b inFormat
\b0 :
\b ETFD_FMT
\b0  \
			   
\b changePath
\b0 :
\b NO
\b0 ];\
			[theWindow 
\b setDocEdited
\b0 :
\b NO
\b0 ];\
		\} else \{\
			[self 
\b saveTo
\b0 :sender 
\b changePath
\b0 :
\b YES
\b0  
\b forceETFD
\b0 :
\b YES
\b0 ];\
		\}\
	\}\
	return self;\
\}\
- 
\b saveAs
\b0 :sender \{\
	[self 
\b saveTo
\b0 :sender 
\b changePath
\b0 :
\b NO
\b0  
\b forceETFD
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b isVirgin
\b0 ]];\
	return self;\
\}\
- 
\b saveTo
\b0 :sender \{\
	if ([self 
\b needsSaving
\b0 ]) \{\
		[self 
\b saveTo
\b0 :sender 
\b changePath
\b0 :
\b YES
\b0  
\b forceETFD
\b0 :
\b YES
\b0 ];\
	\}\
	return self;\
\}\
- 
\b formatAction
\b0 :sender \{				// 
\i Private Callback hook!\

\i0 	
\b static
\b0  
\b BOOL
\b0  
\b _warned
\b0 =NO; \
	const char 	*
\b docdir
\b0 ;\
	id 
\b sp
\b0  = [SavePanel new];\
	\
	int 
\b fmt
\b0  = [[sender 
\b selectedCell
\b0 ] 
\b tag
\b0 ];\
    switch (
\b fmt
\b0 ) \{\
		case 
\b ETFD_FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :
\b ETFD_EXT
\b0 ]; \
			
\b docdir
\b0  = [userModel 
\b stringQuery
\b0 :
\b ETFDIRECTORY
\b0 ];\
			if (docdir && *docdir) \{\
				[sp 
\b setDirectory
\b0 :
\b docdir
\b0 ];\
			\}\
			break;\
		case 
\b HTMD_FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :
\b\fc1\cf1 HTMD
\fc0\cf0 _EXT
\b0 ];\
			if (!
\b _warned
\b0 ) _warned = [
\b userModel
\b0  
\b boolQuery
\b0 :
\b HTMD_WARNED
\b0 ];\
			if (!
\b _warned
\b0 ) \{\
				
\b NXRunAlertPanel
\b0 ("
\b Save as HTMD
\b0 ","
\b Remember to 1) keep them in the same directory and 2) no spaces in filenames.
\b0 ","
\b OK
\b0 ",NULL,NULL);\
				
\b _warned
\b0  = 
\b YES
\b0 ;\
			\}\
			
\b docdir
\b0  = [userModel 
\b stringQuery
\b0 :
\b HTMDIRECTORY
\b0 ];\
			if (docdir && *docdir) \{\
				[sp 
\b setDirectory
\b0 :
\b docdir
\b0 ];\
			\}\
			break;\
		case 
\b ASCII_FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :
\b ASCII_EXT
\b0 ]; \
			break;\
		case 
\b C_FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :""]; \
			break;\
		case 
\b\fc1\cf1 TeXD
\fc0\cf0 _FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :
\b\fc1\cf1 TeXD
\fc0\cf0 _EXT
\b0 ]; \
			break;\
		case 
\b RTF_FMT
\b0 :\
			[sp 
\b setRequiredFileType
\b0 :
\b RTF_EXT
\b0 ]; \
			break;\
    \}\
    return self;\
\}\
- 
\b saveTo
\b0 :sender 
\b changePath
\b0 :(
\b BOOL
\b0 ) changeIt 
\b forceETFD
\b0 :(
\b BOOL
\b0 ) forceIt\
\{\
	char 			
\b p
\b0 [MAXPATHLEN], *
\b f
\b0 =NULL;\
	int				
\b fmt
\b0 ;\
	id 				
\b savepanel
\b0  = [
\b SavePanel
\b0  
\b new
\b0 ];\
	static id		
\b formatPopup
\b0  = nil, 
\b formatButton
\b0  = nil; \
	\
	// 
\i PHASE 0: Creating a formatPicker
\i0 \
	if (!
\b formatPopup
\b0 ) \{\
		char 
\b item
\b0 [MAXPATHLEN];\
		\
		formatPopup = [[
\b PopUpList
\b0  alloc] 
\b init
\b0 ];\
		[formatPopup 
\b changeButtonTitle
\b0 :
\b YES
\b0 ];\
		[formatPopup 
\b setAction
\b0 :@selector(
\b formatAction:
\b0 )];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b ETFD_DESC, ETFD_EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b ETFD_FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 1
\b0 '];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b\fc1\cf1 HTMD
\fc0\cf0 _DESC, 
\fc1\cf1 HTMD
\fc0\cf0 _EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b\fc1\cf1 HTMD
\fc0\cf0 _FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 2
\b0 '];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b\fc1\cf1 TeXD
\fc0\cf0 _DESC, 
\fc1\cf1 TeXD
\fc0\cf0 _EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b\fc1\cf1 TeXD
\fc0\cf0 _FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 3
\b0 '];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b RTF_DESC, 
\fc1\cf1 RTF
\fc0\cf0 _EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b\fc1\cf1 RTF
\fc0\cf0 _FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 4
\b0 '];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b ASCII_DESC, ASCII_EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b ASCII_FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 5
\b0 '];\
		sprintf(item,"
\b %s (.%s)
\b0 ", 
\b C_DESC, C_EXT
\b0 );\
		[[[formatPopup 
\b addItem
\b0 :item] 
\b setTag
\b0 :
\b C_FMT
\b0 ] 
\b setKeyEquivalent
\b0 :'
\b 6
\b0 '];\
		
\b formatButton
\b0  = 
\b NXCreatePopUpListButton
\b0 (
\b formatPopup
\b0 );\
	\}\
	\
	// 
\i PHASE I: Initializing & Running the savePanel\
	
\i0 \
	
\b strcpy
\b0 (
\b p
\b0 , [[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]);\
	if (rindex(p, '
\b .
\b0 ')) *
\b rindex
\b0 (p, '
\b .
\b0 ')= '
\b \\0
\b0 ';\
	if (rindex(p, '
\b /
\b0 ')) \{\
	
\b 	f
\b0  = 
\b rindex
\b0 (p, '
\b /
\b0 ')
\b +1
\b0 ;\
		*
\b rindex
\b0 (p, '
\b /
\b0 ')= '
\b \\0
\b0 ';\
   	\} \
\
	[savepanel setDirectory:
\b p
\b0 ];		// 
\i First crack; htmld or etfd may chdir
\i0 \
	[
\b formatPopup
\b0  
\b setTarget
\b0 :
\b self
\b0 ];\
	if (
\b forceIt
\b0 ) \{\
		[savepanel setTitle:"
\b Save/eText Format
\b0 "];\
		[savepanel setAccessoryView:
\b nil
\b0 ];\
		[savepanel 
\b setRequiredFileType
\b0 :
\b\fc1\cf1 ETFD
\fc0\cf0 _EXT
\b0 ];\
	\} else \{\
		[savepanel setTitle:"
\b Save/Any Format
\b0 "];\
		[savepanel setAccessoryView:
\b formatButton
\b0 ];\
		[self 
\b formatAction
\b0 :[
\b formatPopup
\b0  
\b itemList
\b0 ]];\
	\}\
	if (![savepanel 
\b runModalForDirectory
\b0 :[savepanel directory] 
\b file
\b0 :
\b f
\b0 ])\
		return 
\b nil
\b0 ;\
\
	// 
\i PHASE II: Consistency Checks, write datafiles
\i0 \
	
\b fmt
\b0  = (
\b forceIt
\b0 ) ? 
\b ETFD_FMT
\b0  :[[[
\b formatPopup
\b0  
\b itemList
\b0 ] 
\b selectedCell
\b0 ] 
\b tag
\b0 ];\
	
\b strcpy
\b0 (
\b p
\b0 ,[savepanel 
\b filename
\b0 ]);\
	\
	if (
\b fmt
\b0 ==
\b HTMD_FMT
\b0 ) \{\
		
\b sprintf
\b0 (
\b p
\b0 , "
\b %s/%s
\b0 ",[savepanel 
\b directory
\b0 ], rindex([[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ],'
\b /
\b0 ')+
\b 1
\b0 );\
		*(rindex(
\b p
\b0 ,'
\b .
\b0 ')+1) = '\\0';\
		strcat(
\b p
\b0 , 
\b HTMD_EXT
\b0 );\
		if (
\b strcmp
\b0 (
\b p
\b0 , [savepanel 
\b filename
\b0 ])) \{\
			//
\i  i.e. is the basename != the original pathname (for link anchors)
\i0 \
			int 
\b choice
\b0  = 
\b NXRunAlertPanel
\b0 ( "
\b Save As HTMD
\b0 ",\
				"
\b You must use the filename %s to make links to this document.
\b0 ", \
				"
\b OK
\b0 ", "
\b Shut Up And Do What I Said
\b0 ", NULL, 
\b p
\b0 );\
			if(choice==
\b NX_ALERTALTERNATE
\b0 )\
				strcpy(
\b p
\b0 ,[savepanel 
\b filename
\b0 ]); // 
\i do what the bonehead sez...
\i0 \
		\}\
	\}\
	\
	[
\b etDoc
\b0  
\b saveTo
\b0 :
\b p
\b0  
\b inFormat
\b0 :
\b fmt
\b0  
\b changePath
\b0 :changeIt];\
	if (fmt == 
\b ETFD_FMT
\b0 ) \{\
		[theWindow 
\b setDocEdited
\b0 :
\b NO
\b0 ];\
		[theWindow 
\b setTitleAsFilename
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]];\
	\}\
	return self;\
	\
\}\
\
- 
\b close
\b0 :sender \{\
	return [self 
\b close
\b0 :sender 
\b allowCancel
\b0 :
\b YES
\b0 ];\}\
- 
\b close
\b0 :sender 
\b allowCancel
\b0 :(
\b BOOL
\b0 )cancellable\
\{\
	//
\i 	Run a possible alert panel
\i0 \
	if ([self 
\b needsSaving
\b0 ]) \{\
		const char *
\b name
\b0 ;\
		int 		
\b choice
\b0 ;\
		\
		if (*[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ])\
			
\b name
\b0  = 
\b rindex
\b0 ([[etDoc docInfo] 
\b docPath
\b0 ], '
\b /
\b0 ')+1;\
		else \
			name = NXUniqueString("
\b Untitled
\b0 ");\
		choice = NXRunAlertPanel("
\b Close
\b0 ","
\b Save changes to %s?
\b0 ",\
				"
\b Save
\b0 ", "
\b Don't Save
\b0 ", 
\b\i cancellable
\b0  ? "
\b Cancel
\b0 " : 
\b NULL
\b0\i0 , 
\b name
\b0 );\
		switch (choice) \{\
			case 
\b NX_ALERTDEFAULT
\b0 :	[self 
\b save
\b0 :self];\
									break;\
			case 
\b NX_ALERTOTHER
\b0 :	return 
\b nil
\b0 ;\
		\}\
	\}\
	// 	
\i The actual closing begins from eTApp
\i0 \
	[
\b etApp
\b0  	
\b perform
\b0 :@selector(
\b closeID:
\b0 ) 
\b with
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docID
\b0 ]\
			
\b afterDelay
\b0 :
\b 0
\b0  
\b cancelPrevious
\b0 :
\b NO
\b0 ];\
	return self;\
\}\
\
- 
\b revert
\b0 :sender\
\{\
	int 		
\b choice
\b0 ;\
	const char	*
\b name
\b0 ;\
	
\b NXSelPt
\b0 		
\b bPt
\b0 , 
\b ePt
\b0 ;\
\
	//	
\i PHASE I: Run a possible alert panel
\i0 \
	if (*[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ])\
		
\b name
\b0  = 
\b rindex
\b0 ([[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ], '
\b /
\b0 ')+1;\
	else \{\
		
\b NXBeep
\b0 (); return 
\b nil
\b0 ;\}	\
		\
	if ([self 
\b needsSaving
\b0 ] && 
\b name
\b0 ) \{\
		choice =
\b NXRunAlertPanel
\b0 ("
\b Revert
\b0 ","
\b Discard changes to the document %s?
\b0 ",\
					"
\b Revert
\b0 ", "
\b Cancel
\b0 ", NULL, 
\b name
\b0 );\
    	if (choice==
\b NX_ALERTALTERNATE
\b0 ) \{return 
\b nil
\b0 ;\}\
 	\}\
\
	//	
\i PHASE II: Reload
\i0 \
	[theWindow 
\b disableDisplay
\b0 ];\
	[eTextObj 
\b getSel
\b0 :&
\b bPt
\b0  :&
\b ePt
\b0 ];\
	begin = bPt.cp; end = ePt.cp;\
	[[etDoc undoManager] 
\b disableUndoRegistration
\b0 ];\
	[[eTextObj 
\b setSel
\b0 :
\b 0
\b0  :[eTextObj 
\b textLength
\b0 ]] 
\b delete
\b0 :self];\
	[[etDoc undoManager] 
\b reenableUndoRegistration
\b0 ];\
	[[etDoc undoManager] 
\b emptyUndoManager
\b0 ];\
	if (
\b theAgent
\b0 ) \{\
		[theContainer 
\b removeFromSuperview
\b0 ];\
		[theContainer 
\b free
\b0 ];\
		theContainer = theAgent = 
\b nil
\b0 ;\
	\}\
	[
\b eTextObj
\b0  
\b setSel
\b0 :
\b begin
\b0  :
\b end
\b0 ];\
	[theWindow 
\b setDocEdited
\b0 :
\b NO
\b0 ];\
	[etDoc 
\b setSelectedObj
\b0 :
\b nil
\b0 ];\
	[
\b inspector
\b0  
\b inspect
\b0 :
\b nil
\b0 ];\
	[[theWindow 
\b reenableDisplay
\b0 ] 
\b display
\b0 ];\
	return self;\
\}\
- 
\b print
\b0 :sender\
\{\
	[
\b eTextObj
\b0  
\b printPSCode
\b0 :sender];\
	return self;\
\}\
\
- (BOOL)
\b validateCommand
\b0 :(MenuCell *)menuCell\
\{	\
    SEL 
\b action
\b0  = [
\b menuCell
\b0  
\b action
\b0 ];\
	BOOL 
\b enable
\b0 ;\
	static NXAtom 
\b removeAgent
\b0  = 
\b NULL
\b0 ;\
	\
	if (!
\b removeAgent
\b0 ) 
\b removeAgent
\b0  = NXUniqueString("
\b Detach Agent
\b0 ");\
	\
	if (NXUniqueString([menuCell title])==
\b removeAgent
\b0 ) \{\
		enable = (
\b theAgent?YES:NO
\b0 );\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
	\} else if ((action == @selector(
\b revert:
\b0 )) ||\
				(action == @selector(
\b save:
\b0 ))) \{\
		enable = [self 
\b needsSaving
\b0 ];\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
	\} else if ((action == @selector(
\b saveAs:
\b0 )) ||\
				(action == @selector(
\b saveTo:
\b0 )) ||\
				(action == @selector(
\b print:
\b0 ))  ||\
				(action == @selector(
\b close:
\b0 ))) \{\
		enable = 
\b YES
\b0 ;\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
	\} else if (action == @selector(
\b undo:
\b0 )) \{\
 		char buf[256];\
\
		if (
\b !
\b0 [[etDoc undoManager] 
\b lastUndoName
\b0 ])\{\
			if ([menuCell 
\b isEnabled
\b0 ]) \{\
				[menuCell setTitle:"
\b Undo
\b0 "];\
				[menuCell setEnabled:
\b NO
\b0 ];\

\b 				
\b0 return
\b  YES;
\b0 \
			\}
\b \

\b0    		\} else \{\
			sprintf(buf, "
\b Undo %s
\b0 ", [[etDoc 
\b undoManager
\b0 ] 
\b lastUndoName
\b0 ]);\
			if (
\b strcmp
\b0 (buf, [menuCell title])) \{\
				[menuCell 
\b setTitle
\b0 :buf];\
				[menuCell 
\b setEnabled
\b0 :YES];\
				return 
\b YES
\b0 ;\
			\}\
		\}\
	\} else if(action == @selector(
\b redo:
\b0 ))\{\
 		char buf[256];\
\
		if (
\b !
\b0 [[etDoc undoManager] 
\b lastRedoName
\b0 ])\{\
			if ([menuCell 
\b isEnabled
\b0 ]) \{\
				[menuCell setTitle:"
\b Redo
\b0 "];\
				[menuCell setEnabled:
\b NO
\b0 ];\

\b 				
\b0 return
\b  YES;
\b0 \
			\}
\b \

\b0    		\} else \{\
			sprintf(buf, "
\b Redo %s
\b0 ", [[etDoc 
\b undoManager
\b0 ] 
\b lastRedoName
\b0 ]);\
			if (
\b strcmp
\b0 (buf, [menuCell title])) \{\
				[menuCell 
\b setTitle
\b0 :buf];\
				[menuCell 
\b setEnabled
\b0 :YES];\
				return 
\b YES
\b0 ;\
			\}\
		\}\
	\} else \{\
		return 
\b NO
\b0 ;\
	\}\
	return 
\b NO
\b0 ;\
\}\
\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
// 	
\b Window Management & Callbacks
\b0 \
//\
- 
\b touch 
\b0 \{\
	[theWindow 
\b setDocEdited
\b0 :
\b YES
\b0 ]; return self;\}\
- (
\b BOOL
\b0 ) 
\b needsSaving
\b0  \{\
	return [theWindow 
\b isDocEdited
\b0 ];\}\
\
- 
\b windowWillClose
\b0 :sender \{\
	[self 	
\b perform
\b0 :@selector(
\b close:
\b0 ) 
\b with
\b0 :
\b sender
\b0  \
			
\b afterDelay
\b0 :
\b 0
\b0  
\b cancelPrevious
\b0 :
\b YES
\b0 ];\
	return 
\b nil
\b0 ;\
\}\
- 
\b windowDidBecomeKey
\b0 :sender \{\
	if (
\b printInfo
\b0 ) [NXApp 
\b setPrintInfo
\b0 :
\b printInfo
\b0 ];\
	[
\b inspector
\b0  
\b inspect
\b0 :[etDoc 
\b selectedObj
\b0 ]];\
	//NXLogError("%x promoted; inspected %s %x", self, [[[etDoc 
\b selectedObj
\b0 ] class] name], [etDoc 
\b selectedObj
\b0 ]);\
	return self;\
\}\
- 
\b windowDidResignKey
\b0 :sender \{\
	[
\b etDoc
\b0  
\b setSelectedObj
\b0 :[inspector 
\b currentObj
\b0 ]]; // 
\i can't prove this works
\i0 \
	//NXLogError("%x demoted; cached %s %x", self, [[[etDoc 
\b selectedObj
\b0 ] class] name], [etDoc 
\b selectedObj
\b0 ]);\
	return self;\
\}\

\fc1\cf1 - 
\b windowWillMiniaturize
\b0 :(Window *)sender 
\b toMiniwindow
\b0 :counterpart \{\
	[sender 
\b setMiniwindowIcon
\b0 :"eTApp"];\
    return self;\
\}\

\fc0\cf0 \
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
// 	
\b Public Accessors & API
\b0 \
//\
- 
\b eTextObj
\b0  \{\
	return 
\b eTextObj
\b0 ;\}\
- 
\b scroller
\b0  \{\
	return 
\b theScroller
\b0 ;\}\
- 
\b etDoc
\b0  \{\
	return 
\b etDoc
\b0 ;\}\
- 
\b window
\b0  \{\
	return 
\b theWindow
\b0 ;\}\
\
- 
\b attachAgent
\b0 :newAgent \{\
	NXRect frame;\
	NXSize sz;\
\
	//	
\i PHASE I: Do we have to throw out the old one?
\i0 	\
	if (theAgent) \{\
		int 
\b choice
\b0  = 
\b NXRunAlertPanel
\b0 ("
\b Attach Agent
\b0 ",\
					"
\b Are you sure you want to replace the agent currently"\
					" working with this document?
\b0 ",\
					"
\b Replace
\b0 ", "
\b Cancel
\b0 ", NULL);\
		if (choice == 
\b NX_ALERTALTERNATE
\b0 ) \{return 
\b nil
\b0 ;\}\
	\}\
	[theWindow 
\b disableDisplay
\b0 ];\
	if (
\b theAgent
\b0 ) \{\

\i 	//	[[[undoManager setUndoTarget:self] freeUndoArgs] attachAgent:theAgent];\
	//	[undoManager setUndoName:"Replace Agent"];\
	//	[undoManager setRedoName:"Replace Agent"];\

\i0 		[
\b theContainer
\b0  
\b removeFromSuperview
\b0 ];\
		theContainer = [theContainer 
\b free
\b0 ];\
		[
\b theSplitview
\b0  
\b setDelegate
\b0 :
\b self
\b0 ];\
		theContainer = theAgent = 
\b nil
\b0 ;\
	\} else \{\

\i 	//	[[undoManager setUndoTarget:self] detachAgent];\
	//	[undoManager setUndoName:"Attach Agent"];\
	//	[undoManager setRedoName:"Attach Agent"];\

\i0 	\}\
	//	
\i PHASE II: Find the new agent -- either in sender or tables
\i0 \
	if ([
\b newAgent
\b0  
\b conformsTo
\b0 :@protocol(
\b Agent
\b0 )])\
		
\b theAgent
\b0  = 
\b newAgent
\b0 ;\
	[[theAgent 
\b controlView
\b0 ] 
\b getFrame
\b0 :&frame];\
	
\b theContainer
\b0  = [[
\b eTContainerView
\b0  alloc] 
\b initFrame
\b0 :&frame];\
	[theContainer 
\b attachAgent
\b0 :theAgent];\
	[
\b theSplitview
\b0  
\b setDelegate
\b0 :theContainer];\
	[theSplitview 
\b addSubview
\b0 :
\b theContainer
\b0 ];\
	[theContainer 
\b getMinSize
\b0 :&
\b sz
\b0 ];\
	sz.width += 
\b 30.0
\b0 ;\
	sz.height += 
\b 230.0
\b0 ;\
	[
\b theWindow
\b0  
\b setMinSize
\b0 :&
\b sz
\b0 ];\
	[[theWindow 
\b reenableDisplay
\b0 ] 
\b display
\b0 ];\
	return self;\
\}\
\
- 
\b detachAgent
\b0  \{\
	[theWindow 
\b disableDisplay
\b0 ];\
	if (
\b theAgent
\b0 ) \{\

\i 	//	[[[undoManager setUndoTarget:self] freeUndoArgs] attachAgent:theAgent];\
	//	[undoManager setUndoName:"Reattach Agent"];\
	//	[undoManager setRedoName:"Reattach Agent"];
\i0 \
		[
\b theContainer
\b0  
\b removeFromSuperview
\b0 ];\
		[theContainer 
\b free
\b0 ];\
		[
\b theSplitview
\b0  
\b setDelegate
\b0 :
\b self
\b0 ];\
		theContainer = theAgent = 
\b nil
\b0 ;\
	\}\
	[[theWindow 
\b reenableDisplay
\b0 ] 
\b display
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b <DocNotification> Obligations for .etUInfo
\b0 \
//\
- 
\b docWillWrite
\b0 :sender\
\{\
	
\b NXSelPt
\b0 		
\b bPt
\b0 , 
\b ePt
\b0 ;\
\
	[
\b eTextObj
\b0  
\b getSel
\b0 :&
\b bPt
\b0  :&
\b ePt
\b0 ];\
	
\b begin
\b0  = bPt.cp; 
\b end
\b0  = ePt.cp;\
	return self;\
\}\
- 
\b writeComponentToPath
\b0 :(NXAtom)path 
\b inFormat
\b0 :(int) theFormat\
\{\
	char 
\b filename
\b0 [MAXPATHLEN];\
	NXStream *s;\
	NXRect r;\
	float f;\
\
	if (theFormat != 
\b ETFD_FMT
\b0 ) return 
\b self
\b0 ;\
	
\b sprintf
\b0 (filename, "
\b %s/
\b0 "
\b UIINFOFILE
\b0 , 
\b path
\b0 );\
	s = 
\b NXOpenTypedStreamForFile
\b0 (
\b filename
\b0 , NX_WRITEONLY);\
	[theWindow 
\b getFrame
\b0 :&
\b r
\b0 ];\
	
\b NXWriteRootObject
\b0 (s, 
\b printInfo
\b0 );\
	f = [theSplitview 
\b dividerHeight
\b0 ];\
	NXWriteTypes(s,"
\b fffii
\b0 ", &
\b f
\b0 , &(
\b r
\b0 .size.height),\
		&(
\b r
\b0 .size.width), &(
\b begin
\b0 ), &(
\b end
\b0 ));\
	
\b NXCloseTypedStream
\b0 (s);\
	[etDoc 
\b registerComponent
\b0 :NXUniqueString(
\b UIINFOFILE
\b0 )];\
	return self;\
\}\
\

\i @end
}
